---
layout: api-page
title: "request/GetRequestV2.js"
id: api
---

<main class="api-documentation-page">
  

  
  
      
<h2>
    request/GetRequestV2.js
</h2>
<section>
    <article>
        <pre class="prettyprint source linenums"><code>var complement = require("./complement");
var flushGetRequest = require("./flushGetRequest");
var incrementVersion = require("../support/incrementVersion");
var currentCacheVersion = require("../support/currentCacheVersion");

var REQUEST_ID = 0;
var GetRequestType = require("./RequestTypes").GetRequest;
var setJSONGraphs = require("./../set/setJSONGraphs");
var setPathValues = require("./../set/setPathValues");
var $error = require("./../types/error");
var emptyArray = [];
var InvalidSourceError = require("./../errors/InvalidSourceError");

/**
 * Creates a new GetRequest.  This GetRequest takes a scheduler and
 * the request queue.  Once the scheduler fires, all batched requests
 * will be sent to the server.  Upon request completion, the data is
 * merged back into the cache and all callbacks are notified.
 *
 * @param {Scheduler} scheduler -
 * @param {RequestQueueV2} requestQueue -
 */
var GetRequestV2 = function(scheduler, requestQueue) {
    this.sent = false;
    this.scheduled = false;
    this.requestQueue = requestQueue;
    this.id = ++REQUEST_ID;
    this.type = GetRequestType;

    this._scheduler = scheduler;
    this._pathMap = {};
    this._optimizedPaths = [];
    this._requestedPaths = [];
    this._callbacks = [];
    this._count = 0;
    this._disposable = null;
    this._collapsed = null;
    this._disposed = false;
};

GetRequestV2.prototype = {
    /**
     * batches the paths that are passed in.  Once the request is complete,
     * all callbacks will be called and the request will be removed from
     * parent queue.
     * @param {Array} requestedPaths -
     * @param {Array} optimizedPaths -
     * @param {Function} callback -
     */
    batch: function(requestedPaths, optimizedPaths, callback) {
        var self = this;
        var oPaths = self._optimizedPaths;
        var rPaths = self._requestedPaths;
        var callbacks = self._callbacks;
        var idx = oPaths.length;

        // If its not sent, simply add it to the requested paths
        // and callbacks.
        oPaths[idx] = optimizedPaths;
        rPaths[idx] = requestedPaths;
        callbacks[idx] = callback;
        ++self._count;

        // If it has not been scheduled, then schedule the action
        if (!self.scheduled) {
            self.scheduled = true;

            var flushedDisposable;
            var scheduleDisposable = self._scheduler.schedule(function() {
                flushedDisposable = flushGetRequest(self, oPaths, function(err, data) {
                    var i, fn, len;
                    var model = self.requestQueue.model;
                    self.requestQueue.removeRequest(self);
                    self._disposed = true;

                    if (model._treatDataSourceErrorsAsJSONGraphErrors ? err instanceof InvalidSourceError : !!err) {
                        for (i = 0, len = callbacks.length; i &lt; len; ++i) {
                            fn = callbacks[i];
                            if (fn) {
                                fn(err);
                            }
                        }
                        return;
                    }

                    // If there is at least one callback remaining, then
                    // callback the callbacks.
                    if (self._count) {
                        // currentVersion will get added to each inserted
                        // node as node.$_version inside of self._merge.
                        //
                        // atom values just downloaded with $expires: 0
                        // (now-expired) will get assigned $_version equal
                        // to currentVersion, and checkCacheAndReport will
                        // later consider those nodes to not have expired
                        // for the duration of current event loop tick
                        //
                        // we unset currentCacheVersion after all callbacks
                        // have been called, to ensure that only these
                        // particular callbacks and any synchronous model.get
                        // callbacks inside of these, get the now-expired
                        // values
                        var currentVersion = incrementVersion.getCurrentVersion();
                        currentCacheVersion.setVersion(currentVersion);
                        var mergeContext = {hasInvalidatedResult : false};

                        var pathsErr = model._useServerPaths &amp;&amp; data &amp;&amp; data.paths === undefined ?
                            new Error("Server responses must include a 'paths' field when Model._useServerPaths === true") : undefined;

                        if (!pathsErr) {
                            self._merge(rPaths, err, data, mergeContext);
                        }

                        // Call the callbacks.  The first one inserts all
                        // the data so that the rest do not have consider
                        // if their data is present or not.
                        for (i = 0, len = callbacks.length; i &lt; len; ++i) {
                            fn = callbacks[i];
                            if (fn) {
                                fn(pathsErr || err, data, mergeContext.hasInvalidatedResult);
                            }
                        }
                        currentCacheVersion.setVersion(null);
                    }
                });
                self._disposable = flushedDisposable;
            });

            // If the scheduler is sync then `flushedDisposable` will be
            // defined, and we want to use it, because that's what aborts an
            // in-flight XHR request, for example.
            // But if the scheduler is async, then `flushedDisposable` won't be
            // defined yet, and so we must use the scheduler's disposable until
            // `flushedDisposable` is defined. Since we want to still use
            // `flushedDisposable` once it is defined (to be able to abort in-
            // flight XHR requests), hence the reassignment of `_disposable`
            // above.
            self._disposable = flushedDisposable || scheduleDisposable;
        }

        // Disposes this batched request.  This does not mean that the
        // entire request has been disposed, but just the local one, if all
        // requests are disposed, then the outer disposable will be removed.
        return createDisposable(self, idx);
    },

    /**
     * Attempts to add paths to the outgoing request.  If there are added
     * paths then the request callback will be added to the callback list.
     * Handles adding partial paths as well
     *
     * @returns {Array} - whether new requested paths were inserted in this
     *                    request, the remaining paths that could not be added,
     *                    and disposable for the inserted requested paths.
     */
    add: function(requested, optimized, depthDifferences, callback) {
        // uses the length tree complement calculator.
        var self = this;
        var complementTuple = complement(requested, optimized, depthDifferences, self._pathMap);
        var optimizedComplement;
        var requestedComplement;

        if (complementTuple) {
            requestedComplement = complementTuple[2];
            optimizedComplement = complementTuple[1];
        } else {
            requestedComplement = requested;
            optimizedComplement = optimized;
        }

        var inserted = false;
        var disposable = false;

        // If we found an intersection, then just add new callback
        // as one of the dependents of that request
        if (complementTuple &amp;&amp; complementTuple[0].length) {
            inserted = true;
            var idx = self._callbacks.length;
            self._callbacks[idx] = callback;
            self._requestedPaths[idx] = complementTuple[0];
            self._optimizedPaths[idx] = [];
            ++self._count;

            disposable = createDisposable(self, idx);
        }

        return [inserted, requestedComplement, optimizedComplement, disposable];
    },

    /**
     * merges the response into the model"s cache.
     */
    _merge: function(requested, err, data, mergeContext) {
        var self = this;
        var model = self.requestQueue.model;
        var modelRoot = model._root;
        var errorSelector = modelRoot.errorSelector;
        var comparator = modelRoot.comparator;
        var boundPath = model._path;

        model._path = emptyArray;

        // flatten all the requested paths, adds them to the
        var nextPaths = model._useServerPaths ? data.paths : flattenRequestedPaths(requested);

        // Insert errors in every requested position.
        if (err &amp;&amp; model._treatDataSourceErrorsAsJSONGraphErrors) {
            var error = err;

            // Converts errors to objects, a more friendly storage
            // of errors.
            if (error instanceof Error) {
                error = {
                    message: error.message
                };
            }

            // Not all errors are value $types.
            if (!error.$type) {
                error = {
                    $type: $error,
                    value: error
                };
            }

            var pathValues = nextPaths.map(function(x) {
                return {
                    path: x,
                    value: error
                };
            });
            setPathValues(model, pathValues, null, errorSelector, comparator, mergeContext);
        }

        // Insert the jsonGraph from the dataSource.
        else {
            setJSONGraphs(model, [{
                paths: nextPaths,
                jsonGraph: data.jsonGraph
            }], null, errorSelector, comparator, mergeContext);
        }

        // return the model"s boundPath
        model._path = boundPath;
    }
};

// Creates a more efficient closure of the things that are
// needed.  So the request and the idx.  Also prevents code
// duplication.
function createDisposable(request, idx) {
    var disposed = false;
    return function() {
        if (disposed || request._disposed) {
            return;
        }

        disposed = true;
        request._callbacks[idx] = null;
        request._optimizedPaths[idx] = [];
        request._requestedPaths[idx] = [];

        // If there are no more requests, then dispose all of the request.
        var count = --request._count;
        var disposable = request._disposable;
        if (count === 0) {
            // looking for unsubscribe here to support more data sources (Rx)
            if (disposable.unsubscribe) {
                disposable.unsubscribe();
            } else {
                disposable.dispose();
            }
            request.requestQueue.removeRequest(request);
        }
    };
}

function flattenRequestedPaths(requested) {
    var out = [];
    var outLen = -1;
    for (var i = 0, len = requested.length; i &lt; len; ++i) {
        var paths = requested[i];
        for (var j = 0, innerLen = paths.length; j &lt; innerLen; ++j) {
            out[++outLen] = paths[j];
        }
    }
    return out;
}

module.exports = GetRequestV2;
</code></pre>
    </article>
</section>
  

  
</main>



        
        <!--
          In case someone comes along later and sees the active item on the
          toc acting weirdly, hopefully they'll see this comment. This page, unlike
          any seen during development, has multiple 'docs' passed to container.tmpl.
          To debug it and enhance the page as needed, I would suggest looking there first.
        -->
        

        <!-- Generate the table of contents -->
        <nav class="table-of-contents api-doc-toc">
            <ul class="nav">
                <li>
                    <a href="DataSource.html">Classes</a>
                    <ul class="toc-api-classes">
                        
                            <li class="toc-api-class ">
                                <a href="DataSource.html" data-target="#DataSource">DataSource</a>
                                
                                

    <ul class="toc-api-subgroup toc-api-subgroup-methods">
        <li>
            <span class="toc-api-subgroup-title">Methods</span>
        </li>
        
            <li class="toc-api-subgroup-item">
                <a href="DataSource.html#call" data-target="#call">call</a>
            </li>
        
            <li class="toc-api-subgroup-item">
                <a href="DataSource.html#get" data-target="#get">get</a>
            </li>
        
            <li class="toc-api-subgroup-item">
                <a href="DataSource.html#set" data-target="#set">set</a>
            </li>
         
    </ul>


                                


                                


                            </li>
                        
                            <li class="toc-api-class ">
                                <a href="FromEsObserverAdapter.html" data-target="#FromEsObserverAdapter">FromEsObserverAdapter</a>
                                
                                


                                


                                


                            </li>
                        
                            <li class="toc-api-class ">
                                <a href="HttpDataSource.html" data-target="#HttpDataSource">HttpDataSource</a>
                                
                                

    <ul class="toc-api-subgroup toc-api-subgroup-methods">
        <li>
            <span class="toc-api-subgroup-title">Methods</span>
        </li>
        
            <li class="toc-api-subgroup-item">
                <a href="HttpDataSource.html#call" data-target="#call">call</a>
            </li>
        
            <li class="toc-api-subgroup-item">
                <a href="HttpDataSource.html#get" data-target="#get">get</a>
            </li>
        
            <li class="toc-api-subgroup-item">
                <a href="HttpDataSource.html#set" data-target="#set">set</a>
            </li>
         
    </ul>


                                


                                


                            </li>
                        
                            <li class="toc-api-class ">
                                <a href="Model.html" data-target="#Model">Model</a>
                                
                                

    <ul class="toc-api-subgroup toc-api-subgroup-methods">
        <li>
            <span class="toc-api-subgroup-title">Methods</span>
        </li>
        
            <li class="toc-api-subgroup-item">
                <a href="Model.html#_setMaxSize" data-target="#_setMaxSize">_setMaxSize</a>
            </li>
        
            <li class="toc-api-subgroup-item">
                <a href="Model.html#asDataSource" data-target="#asDataSource">asDataSource</a>
            </li>
        
            <li class="toc-api-subgroup-item">
                <a href="Model.html#batch" data-target="#batch">batch</a>
            </li>
        
            <li class="toc-api-subgroup-item">
                <a href="Model.html#boxValues" data-target="#boxValues">boxValues</a>
            </li>
        
            <li class="toc-api-subgroup-item">
                <a href="Model.html#call" data-target="#call">call</a>
            </li>
        
            <li class="toc-api-subgroup-item">
                <a href="Model.html#deref" data-target="#deref">deref</a>
            </li>
        
            <li class="toc-api-subgroup-item">
                <a href="Model.html#get" data-target="#get">get</a>
            </li>
        
            <li class="toc-api-subgroup-item">
                <a href="Model.html#getCache" data-target="#getCache">getCache</a>
            </li>
        
            <li class="toc-api-subgroup-item">
                <a href="Model.html#getPath" data-target="#getPath">getPath</a>
            </li>
        
            <li class="toc-api-subgroup-item">
                <a href="Model.html#getVersion" data-target="#getVersion">getVersion</a>
            </li>
        
            <li class="toc-api-subgroup-item">
                <a href="Model.html#invalidate" data-target="#invalidate">invalidate</a>
            </li>
        
            <li class="toc-api-subgroup-item">
                <a href="Model.html#preload" data-target="#preload">preload</a>
            </li>
        
            <li class="toc-api-subgroup-item">
                <a href="Model.html#set" data-target="#set">set</a>
            </li>
        
            <li class="toc-api-subgroup-item">
                <a href="Model.html#setCache" data-target="#setCache">setCache</a>
            </li>
        
            <li class="toc-api-subgroup-item">
                <a href="Model.html#treatErrorsAsValues" data-target="#treatErrorsAsValues">treatErrorsAsValues</a>
            </li>
        
            <li class="toc-api-subgroup-item">
                <a href="Model.html#unbatch" data-target="#unbatch">unbatch</a>
            </li>
        
            <li class="toc-api-subgroup-item">
                <a href="Model.html#unboxValues" data-target="#unboxValues">unboxValues</a>
            </li>
        
            <li class="toc-api-subgroup-item">
                <a href="Model.html#withoutDataSource" data-target="#withoutDataSource">withoutDataSource</a>
            </li>
         
    </ul>


                                

    <ul class="toc-api-subgroup toc-api-subgroup-types">
        <li>
            <span class="toc-api-subgroup-title">Types</span>
        </li>
        
            <li class="toc-api-subgroup-item">
                <a href="Model.html#~comparator" data-target="#\~comparator">comparator</a>
            </li>
        
            <li class="toc-api-subgroup-item">
                <a href="Model.html#~errorSelector" data-target="#\~errorSelector">errorSelector</a>
            </li>
        
            <li class="toc-api-subgroup-item">
                <a href="Model.html#~onChange" data-target="#\~onChange">onChange</a>
            </li>
         
    </ul>


                                


                            </li>
                        
                            <li class="toc-api-class ">
                                <a href="ModelResponse.html" data-target="#ModelResponse">ModelResponse</a>
                                
                                

    <ul class="toc-api-subgroup toc-api-subgroup-methods">
        <li>
            <span class="toc-api-subgroup-title">Methods</span>
        </li>
        
            <li class="toc-api-subgroup-item">
                <a href="ModelResponse.html#forEach" data-target="#forEach">forEach</a>
            </li>
        
            <li class="toc-api-subgroup-item">
                <a href="ModelResponse.html#progressively" data-target="#progressively">progressively</a>
            </li>
        
            <li class="toc-api-subgroup-item">
                <a href="ModelResponse.html#subscribe" data-target="#subscribe">subscribe</a>
            </li>
         
    </ul>


                                


                                


                            </li>
                        
                            <li class="toc-api-class ">
                                <a href="ModelResponseObserver.html" data-target="#ModelResponseObserver">ModelResponseObserver</a>
                                
                                


                                


                                


                            </li>
                        
                            <li class="toc-api-class ">
                                <a href="Observable.html" data-target="#Observable">Observable</a>
                                
                                

    <ul class="toc-api-subgroup toc-api-subgroup-methods">
        <li>
            <span class="toc-api-subgroup-title">Methods</span>
        </li>
        
            <li class="toc-api-subgroup-item">
                <a href="Observable.html#forEach" data-target="#forEach">forEach</a>
            </li>
        
            <li class="toc-api-subgroup-item">
                <a href="Observable.html#subscribe" data-target="#subscribe">subscribe</a>
            </li>
         
    </ul>


                                

    <ul class="toc-api-subgroup toc-api-subgroup-types">
        <li>
            <span class="toc-api-subgroup-title">Types</span>
        </li>
        
            <li class="toc-api-subgroup-item">
                <a href="Observable.html#~onCompletedCallback" data-target="#\~onCompletedCallback">onCompletedCallback</a>
            </li>
        
            <li class="toc-api-subgroup-item">
                <a href="Observable.html#~onErrorCallback" data-target="#\~onErrorCallback">onErrorCallback</a>
            </li>
        
            <li class="toc-api-subgroup-item">
                <a href="Observable.html#~onNextCallback" data-target="#\~onNextCallback">onNextCallback</a>
            </li>
         
    </ul>


                                


                            </li>
                        
                            <li class="toc-api-class ">
                                <a href="Subscription.html" data-target="#Subscription">Subscription</a>
                                
                                

    <ul class="toc-api-subgroup toc-api-subgroup-methods">
        <li>
            <span class="toc-api-subgroup-title">Methods</span>
        </li>
        
            <li class="toc-api-subgroup-item">
                <a href="Subscription.html#dispose" data-target="#dispose">dispose</a>
            </li>
         
    </ul>


                                


                                


                            </li>
                        
                            <li class="toc-api-class ">
                                <a href="ToEsSubscriptionAdapter.html" data-target="#ToEsSubscriptionAdapter">ToEsSubscriptionAdapter</a>
                                
                                


                                


                                


                            </li>
                        
                    </ul>
                </li>
                <li class="toc-api-type-list ">
                    <a href="global.html">Global Types</a>
                    <ul class="toc-api-types">
                        
                            <li class="toc-api-type">
                                <a href="global.html#Atom" data-target="#Atom">Atom</a>
                            </li>
                        
                            <li class="toc-api-type">
                                <a href="global.html#JSONEnvelope" data-target="#JSONEnvelope">JSONEnvelope</a>
                            </li>
                        
                            <li class="toc-api-type">
                                <a href="global.html#JSONGraph" data-target="#JSONGraph">JSONGraph</a>
                            </li>
                        
                            <li class="toc-api-type">
                                <a href="global.html#JSONGraphEnvelope" data-target="#JSONGraphEnvelope">JSONGraphEnvelope</a>
                            </li>
                        
                            <li class="toc-api-type">
                                <a href="global.html#Key" data-target="#Key">Key</a>
                            </li>
                        
                            <li class="toc-api-type">
                                <a href="global.html#KeySet" data-target="#KeySet">KeySet</a>
                            </li>
                        
                            <li class="toc-api-type">
                                <a href="global.html#Path" data-target="#Path">Path</a>
                            </li>
                        
                            <li class="toc-api-type">
                                <a href="global.html#PathSet" data-target="#PathSet">PathSet</a>
                            </li>
                        
                            <li class="toc-api-type">
                                <a href="global.html#PathValue" data-target="#PathValue">PathValue</a>
                            </li>
                        
                            <li class="toc-api-type">
                                <a href="global.html#Range" data-target="#Range">Range</a>
                            </li>
                        
                    </ul>
                </li>
            </ul>
        </nav>





